package com.geekhalo.lego.starter.idempotent;

import com.geekhalo.lego.annotation.idempotent.Idempotent;
import com.geekhalo.lego.core.idempotent.IdempotentExecutorFactory;
import com.geekhalo.lego.core.idempotent.IdempotentMetaParser;
import com.geekhalo.lego.core.idempotent.support.ExecutionRecordRepository;
import com.geekhalo.lego.core.idempotent.support.ExecutionResultSerializer;
import com.geekhalo.lego.core.idempotent.support.IdempotentAnnParser;
import com.geekhalo.lego.core.idempotent.support.IdempotentExecutorFactories;
import com.geekhalo.lego.core.idempotent.support.IdempotentInterceptor;
import com.geekhalo.lego.core.idempotent.support.IdempotentKeyParser;
import com.geekhalo.lego.core.idempotent.support.SimpleExecutionResultSerializer;
import com.geekhalo.lego.core.idempotent.support.SimpleIdempotentExecutorFactory;
import com.geekhalo.lego.core.idempotent.support.SimpleIdempotentKeyParser;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;

import java.util.Map;

/**
 * Created by taoli on 2022/11/5.
 * gitee : https://gitee.com/litao851025/lego
 * 编程就像玩 Lego
 */
public abstract class IdempotentConfigurationSupport {
    @Autowired
    private IdempotentKeyParser idempotentKeyParser;
    @Autowired
    private ExecutionResultSerializer serializer;

    protected IdempotentExecutorFactory createExecutorFactory(ExecutionRecordRepository executionRecordRepository) {
        SimpleIdempotentExecutorFactory simpleIdempotentExecutorFactory
                = new SimpleIdempotentExecutorFactory();
        simpleIdempotentExecutorFactory.setIdempotentKeyParser(this.idempotentKeyParser);
        simpleIdempotentExecutorFactory.setSerializer(this.serializer);
        simpleIdempotentExecutorFactory.setExecutionRecordRepository(executionRecordRepository);
        return simpleIdempotentExecutorFactory;
    }

    @Bean
    public PointcutAdvisor idempotentPointcutAdvisor(IdempotentInterceptor idempotentInterceptor) {
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(new AnnotationMatchingPointcut(null, Idempotent.class),
                idempotentInterceptor);
        advisor.setOrder(0);
        return advisor;
    }

    @Bean
    public IdempotentInterceptor idempotentInterceptor(IdempotentMetaParser parser,
                                                       IdempotentExecutorFactories factories) {
        return new IdempotentInterceptor(parser, factories);
    }

    @Bean
    public IdempotentMetaParser idempotentMetaParser() {
        return new IdempotentAnnParser();
    }

    @Bean
    public IdempotentExecutorFactories idempotentExecutorFactories(
            Map<String, IdempotentExecutorFactory> factoryMap) {
        return new IdempotentExecutorFactories(factoryMap);
    }

    static class IdempotentKeyParserConfiguration {
        
        @Bean
        public IdempotentKeyParser idempotentKeyParser() {
            return new SimpleIdempotentKeyParser();
        }
    }

    static class ExecutionResultSerializerConfiguration {
        
        @Bean
        public ExecutionResultSerializer executionResultSerializer() {
            return new SimpleExecutionResultSerializer();
        }

    }

}
